home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PRINTER / NEWPRT10.ARJ / MEM.C < prev    next >
C/C++ Source or Header  |  1992-01-14  |  15KB  |  742 lines

  1. /*_ mem.c   Fri Jan 26 1990   Modified by: Walter Bright */
  2. /* $Header: /proj/products/merlin/port/RCS/mem.c,v 1.19 89/10/20 14:36:02 bright Exp Locker: bright $ */
  3. /* Memory management package                */
  4.  
  5. #define MEM_DEBUG 1
  6.  
  7. #if VAX11C
  8. #define  __FILE__  "mem.c"
  9. #endif
  10.  
  11. #include    <stdio.h>
  12.  
  13. #if __ZTC__
  14. #include    <stdlib.h>
  15. #include    <io.h>
  16. #else
  17. extern void *malloc();
  18. extern void *calloc();
  19. extern void *realloc();
  20. #endif
  21.  
  22. #ifndef MEM_H
  23. #include    "mem.h"
  24. #endif
  25.  
  26. #ifndef assert
  27. #include    <assert.h>
  28. #endif
  29.  
  30. #if MSC
  31. #include    <dos.h>
  32. #endif
  33.  
  34. #ifndef VAX11C
  35. #ifdef BSDUNIX
  36. #include <strings.h>
  37. #else
  38. #include <string.h>
  39. #endif
  40. #else
  41. extern char *strcpy(),*memcpy();
  42. extern int strlen();
  43. #endif  /* VAX11C */
  44.  
  45. int mem_inited = 0;     /* != 0 if initialized          */
  46.  
  47. static int mem_behavior = MEM_ABORTMSG;
  48. static int (*fp)(_0) = NULL;    /* out-of-memory handler    */
  49. static int mem_count;        /* # of allocs that haven't been free'd    */
  50. static int mem_scount;        /* # of sallocs that haven't been free'd */
  51.  
  52. /* Determine where to send error messages    */
  53. #if MSDOS
  54. #define ferr    stdout    /* stderr can't be redirected with MS-DOS    */
  55. #else
  56. #define ferr    stderr
  57. #endif
  58.  
  59. /*******************************/
  60.  
  61. void mem_setexception(flag,handler_fp)
  62. #if __ZTC__ && __cplusplus
  63. enum MEM_E flag;
  64. #else
  65. int flag;
  66. #endif
  67. int (*handler_fp)(_0);
  68. {
  69.     mem_behavior = flag;
  70.     fp = (mem_behavior == MEM_CALLFP) ? handler_fp : 0;
  71. #if MEM_DEBUG
  72.     assert(0 <= flag && flag <= MEM_RETRY);
  73. #endif
  74. }
  75.  
  76. /*************************
  77.  * This is called when we're out of memory.
  78.  * Returns:
  79.  *    1:    try again to allocate the memory
  80.  *    0:    give up and return NULL
  81.  */
  82.  
  83. static int near mem_exception()
  84. {   int behavior;
  85.  
  86.     behavior = mem_behavior;
  87.     while (1)
  88.     {
  89.     switch (behavior)
  90.     {
  91.         case MEM_ABORTMSG:
  92. #if MSDOS || __OS2__
  93.         /* Avoid linking in buffered I/O */
  94.         {    static char msg[] = "Fatal error: out of memory\r\n";
  95.  
  96.         write(1,msg,sizeof(msg) - 1);
  97.         }
  98. #else
  99.         fputs("Fatal error: out of memory\n",ferr);
  100. #endif
  101.         /* FALL-THROUGH */
  102.         case MEM_ABORT:
  103.         exit(EXIT_FAILURE);
  104.         /* NOTREACHED */
  105.         case MEM_CALLFP:
  106.         assert(fp);
  107.         behavior = (*fp)();
  108.         break;
  109.         case MEM_RETNULL:
  110.         return 0;
  111.         case MEM_RETRY:
  112.         return 1;
  113.         default:
  114.         assert(0);
  115.     }
  116.     }
  117. }
  118.  
  119. /****************************/
  120.  
  121. #if MEM_DEBUG
  122.  
  123. #undef mem_strdup
  124.  
  125. #if PROTOTYPING
  126. char *mem_strdup(const char *s)
  127. #else
  128. char *mem_strdup(s)
  129. const char *s;
  130. #endif
  131. {
  132.     return mem_strdup_debug(s,__FILE__,__LINE__);
  133. }
  134.  
  135. char *mem_strdup_debug(s,file,line)
  136. char *file;
  137. const char *s;
  138. int line;
  139. {
  140.     char *p;
  141.  
  142.     p = s
  143.         ? (char *) mem_malloc_debug((unsigned) strlen(s) + 1,file,line)
  144.         : NULL;
  145.     return p ? strcpy(p,s) : p;
  146. }
  147. #else
  148. #if PROTOTYPING
  149. char *mem_strdup(const char *s)
  150. #else
  151. char *mem_strdup(s)
  152. const char *s;
  153. #endif
  154. {
  155.     char *p;
  156.  
  157.     p = s ? (char *) mem_malloc((unsigned) strlen(s) + 1) : NULL;
  158.     return p ? strcpy(p,s) : p;
  159. }
  160.  
  161. #endif /* MEM_DEBUG */
  162.  
  163. #ifdef MEM_DEBUG
  164.  
  165. static long mem_maxalloc;    /* max # of bytes allocated        */
  166. static long mem_numalloc;    /* current # of bytes allocated        */
  167.  
  168. #define BEFOREVAL    0x12345678    /* value to detect underrun    */
  169. #define AFTERVAL    0x87654321    /* value to detect overrun    */
  170.  
  171. #if SUN || SUN386
  172. static long afterval = AFTERVAL;    /* so we can do &afterval    */
  173. #endif
  174.  
  175. /* The following should be selected to give maximum probability that    */
  176. /* pointers loaded with these values will cause an obvious crash. On    */
  177. /* Unix machines, a large value will cause a segment fault.        */
  178. /* MALLOCVAL is the value to set malloc'd data to.            */
  179.  
  180. #if MSDOS || __OS2__
  181. #define BADVAL        0xFF
  182. #define MALLOCVAL    0xEE
  183. #else
  184. #define BADVAL        0x7A
  185. #define MALLOCVAL    0xEE
  186. #endif
  187.  
  188. /* Disable mapping macros    */
  189. #undef    mem_malloc
  190. #undef    mem_calloc
  191. #undef    mem_realloc
  192. #undef    mem_free
  193.  
  194. /* Create a list of all alloc'ed pointers, retaining info about where    */
  195. /* each alloc came from. This is a real memory and speed hog, but who    */
  196. /* cares when you've got obscure pointer bugs.                */
  197.  
  198. static struct mem_debug
  199. {    struct mh
  200.     { struct mem_debug *Mnext;    /* next in list            */
  201.       struct mem_debug *Mprev;    /* previous value in list    */
  202.       char *Mfile;        /* filename of where allocated        */
  203.       int Mline;        /* line number of where allocated    */
  204.       unsigned Mnbytes;    /* size of the allocation        */
  205.       long Mbeforeval;    /* detect underrun of data        */
  206.     } m;
  207.     char data[1];        /* the data actually allocated        */
  208. } mem_alloclist =
  209. {
  210.    {    (struct mem_debug *) NULL,
  211.     (struct mem_debug *) NULL,
  212.     "noname",
  213.     11111,
  214.     0,
  215.     BEFOREVAL
  216.    },
  217.    AFTERVAL
  218. };
  219.  
  220. /* Convert from a void *to a mem_debug struct.    */
  221. #define mem_ptrtodl(p)    ((struct mem_debug *) ((char *)p - sizeof(struct mh)))
  222.  
  223. /* Convert from a mem_debug struct to a mem_ptr.    */
  224. #define mem_dltoptr(dl)    ((void *) &((dl)->data[0]))
  225.  
  226. #define next        m.Mnext
  227. #define prev        m.Mprev
  228. #define file        m.Mfile
  229. #define line        m.Mline
  230. #define nbytes        m.Mnbytes
  231. #define beforeval    m.Mbeforeval
  232.  
  233. /*****************************
  234.  * Set new value of file,line
  235.  */
  236.  
  237. void mem_setnewfileline(ptr,fil,lin)
  238. void *ptr;
  239. char *fil;
  240. int lin;
  241. {
  242.     struct mem_debug *dl;
  243.  
  244.     dl = mem_ptrtodl(ptr);
  245.     dl->file = fil;
  246.     dl->line = lin;
  247. }
  248.  
  249. /****************************
  250.  * Print out struct mem_debug.
  251.  */
  252.  
  253. static void near mem_printdl(dl)
  254. struct mem_debug *dl;
  255. {
  256. #if LPTR
  257.     fprintf(ferr,"alloc'd from file '%s' line %d nbytes %d ptr x%lx\n",
  258.         dl->file,dl->line,dl->nbytes,mem_dltoptr(dl));
  259. #else
  260.     fprintf(ferr,"alloc'd from file '%s' line %d nbytes %d ptr x%x\n",
  261.         dl->file,dl->line,dl->nbytes,mem_dltoptr(dl));
  262. #endif
  263. }
  264.  
  265. /****************************
  266.  * Print out file and line number.
  267.  */
  268.  
  269. static void near mem_fillin(fil,lin)
  270. char *fil;
  271. int lin;
  272. {
  273.     fprintf(ferr,"File '%s' line %d\n",fil,lin);
  274.     fflush(ferr);
  275. }
  276.  
  277. /****************************
  278.  * If MEM_DEBUG is not on for some modules, these routines will get
  279.  * called.
  280.  */
  281.  
  282. void *mem_calloc(u)
  283. unsigned u;
  284. {
  285.          return mem_calloc_debug(u,__FILE__,__LINE__);
  286. }
  287.  
  288. void *mem_malloc(u)
  289. unsigned u;
  290. {
  291.          return mem_malloc_debug(u,__FILE__,__LINE__);
  292. }
  293.  
  294. void *mem_realloc(p,u)
  295. void *p;
  296. unsigned u;
  297. {
  298.          return mem_realloc_debug(p,u,__FILE__,__LINE__);
  299. }
  300.  
  301. void mem_free(p)
  302. void *p;
  303. {
  304.     mem_free_debug(p,__FILE__,__LINE__);
  305. }    
  306.  
  307.  
  308. /**************************/
  309.  
  310. void mem_freefp(p)
  311. void *p;
  312. {
  313.     mem_free(p);
  314. }
  315.  
  316. /***********************
  317.  * Debug versions of mem_calloc(), mem_free() and mem_realloc().
  318.  */
  319.  
  320. void *mem_malloc_debug(n,fil,lin)
  321. unsigned n;
  322. char *fil;
  323. int lin;
  324. {   void *p;
  325.  
  326.     p = mem_calloc_debug(n,fil,lin);
  327.     if (p)
  328.     memset(p,MALLOCVAL,n);
  329.     return p;
  330. }
  331.  
  332. void *mem_calloc_debug(n,fil,lin)
  333. unsigned n;
  334. char *fil;
  335. int lin;
  336. {
  337.     struct mem_debug *dl;
  338.  
  339.     do
  340.     dl = (struct mem_debug *)
  341.         calloc(sizeof(*dl) + n + sizeof(AFTERVAL) - 1,1);
  342.     while (dl == NULL && mem_exception());
  343.     if (dl == NULL)
  344.     {
  345. #if 0
  346.     printf("Insufficient memory for alloc of %d at ",n);
  347.     mem_fillin(fil,lin);
  348.     printf("Max allocated was: %ld\n",mem_maxalloc);
  349. #endif
  350.     return NULL;
  351.     }
  352.     dl->file = fil;
  353.     dl->line = lin;
  354.     dl->nbytes = n;
  355.     dl->beforeval = BEFOREVAL;
  356. #if SUN || SUN386 /* bus error if we store a long at an odd address */
  357.     memcpy(&(dl->data[n]),&afterval,sizeof(AFTERVAL));
  358. #else
  359.     *(long *) &(dl->data[n]) = AFTERVAL;
  360. #endif
  361.  
  362.     /* Add dl to start of allocation list    */
  363.     dl->next = mem_alloclist.next;
  364.     dl->prev = &mem_alloclist;
  365.     mem_alloclist.next = dl;
  366.     if (dl->next != NULL)
  367.     dl->next->prev = dl;
  368.  
  369.     mem_count++;
  370.     mem_numalloc += n;
  371.     if (mem_numalloc > mem_maxalloc)
  372.     mem_maxalloc = mem_numalloc;
  373.     return mem_dltoptr(dl);
  374. }
  375.  
  376. void mem_free_debug(ptr,fil,lin)
  377. void *ptr;
  378. char *fil;
  379. int lin;
  380. {
  381.     struct mem_debug *dl;
  382.  
  383.     if (ptr == NULL)
  384.         return;
  385. #if 0
  386.     {    fprintf(ferr,"Freeing NULL pointer at ");
  387.         goto err;
  388.     }
  389. #endif
  390.     if (mem_count <= 0)
  391.     {    fprintf(ferr,"More frees than allocs at ");
  392.         goto err;
  393.     }
  394.     dl = mem_ptrtodl(ptr);
  395.     if (dl->beforeval != BEFOREVAL)
  396.     {
  397. #if LPTR
  398.         fprintf(ferr,"Pointer x%lx underrun\n",ptr);
  399. #else
  400.         fprintf(ferr,"Pointer x%x underrun\n",ptr);
  401. #endif
  402.         goto err2;
  403.     }
  404. #if SUN || SUN386 /* Bus error if we read a long from an odd address    */
  405.     if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)
  406. #else
  407.     if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)
  408. #endif
  409.     {
  410. #if LPTR
  411.         fprintf(ferr,"Pointer x%lx overrun\n",ptr);
  412. #else
  413.         fprintf(ferr,"Pointer x%x overrun\n",ptr);
  414. #endif
  415.         goto err2;
  416.     }
  417.     mem_numalloc -= dl->nbytes;
  418.     if (mem_numalloc < 0)
  419.     {    fprintf(ferr,"error: mem_numalloc = %ld, dl->nbytes = %d\n",
  420.             mem_numalloc,dl->nbytes);
  421.         goto err2;
  422.     }
  423.  
  424.     /* Remove dl from linked list    */
  425.     if (dl->prev)
  426.         dl->prev->next = dl->next;
  427.     if (dl->next)
  428.         dl->next->prev = dl->prev;
  429.  
  430.     /* Stomp on the freed storage to help detect references    */
  431.     /* after the storage was freed.                */
  432.     memset((void *) dl,BADVAL,sizeof(*dl) + dl->nbytes);
  433.     mem_count--;
  434.  
  435.     /* Some compilers can detect errors in the heap.    */
  436. #if DLC
  437.     {    int i;
  438.         i = free(dl);
  439.         assert(i == 0);
  440.     }
  441. #else
  442.     free((void *) dl);
  443. #endif
  444.     return;
  445.  
  446. err2:
  447.     mem_printdl(dl);
  448. err:
  449.     fprintf(ferr,"free'd from ");
  450.     mem_fillin(fil,lin);
  451.     assert(0);
  452.     /* NOTREACHED */
  453. }
  454.  
  455. /*******************
  456.  * Debug version of mem_realloc().
  457.  */
  458.  
  459. void *mem_realloc_debug(oldp,n,fil,lin)
  460. void *oldp;
  461. unsigned n;
  462. char *fil;
  463. int lin;
  464. {   void *p;
  465.     struct mem_debug *dl;
  466.  
  467.     if (n == 0)
  468.     {    mem_free_debug(oldp,fil,lin);
  469.     p = NULL;
  470.     }
  471.     else if (oldp == NULL)
  472.     p = mem_malloc_debug(n,fil,lin);
  473.     else
  474.     {
  475.     p = mem_malloc_debug(n,fil,lin);
  476.     if (p != NULL)
  477.     {
  478.         dl = mem_ptrtodl(oldp);
  479.         if (dl->nbytes < n)
  480.         n = dl->nbytes;
  481.         memcpy(p,oldp,n);
  482.         mem_free_debug(oldp,fil,lin);
  483.     }
  484.     }
  485.     return p;
  486. }
  487.  
  488. /***************************/
  489.  
  490. void mem_check(_0)
  491. {   register struct mem_debug *dl;
  492.  
  493.     for (dl = mem_alloclist.next; dl != NULL; dl = dl->next)
  494.     mem_checkptr(mem_dltoptr(dl));
  495. }
  496.  
  497. /***************************/
  498.  
  499. void mem_checkptr(p)
  500. register void *p;
  501. {   register struct mem_debug *dl;
  502.  
  503.     for (dl = mem_alloclist.next; dl != NULL; dl = dl->next)
  504.     {
  505.     if (p >= (void *) &(dl->data[0]) &&
  506.         p < (void *)((char *)dl + sizeof(struct mem_debug)-1 + dl->nbytes))
  507.         goto L1;
  508.     }
  509.     assert(0);
  510.  
  511. L1:
  512.     dl = mem_ptrtodl(p);
  513.     if (dl->beforeval != BEFOREVAL)
  514.     {
  515. #if LPTR
  516.         fprintf(ferr,"Pointer x%lx underrun\n",p);
  517. #else
  518.         fprintf(ferr,"Pointer x%x underrun\n",p);
  519. #endif
  520.         goto err2;
  521.     }
  522. #if SUN || SUN386 /* Bus error if we read a long from an odd address    */
  523.     if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)
  524. #else
  525.     if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)
  526. #endif
  527.     {
  528. #if LPTR
  529.         fprintf(ferr,"Pointer x%lx overrun\n",p);
  530. #else
  531.         fprintf(ferr,"Pointer x%x overrun\n",p);
  532. #endif
  533.         goto err2;
  534.     }
  535.     return;
  536.  
  537. err2:
  538.     mem_printdl(dl);
  539.     assert(0);
  540. }
  541.  
  542. #else
  543.  
  544. /***************************/
  545.  
  546. void *mem_malloc(numbytes)
  547. unsigned numbytes;
  548. {    void *p;
  549.  
  550.     if (numbytes == 0)
  551.         return NULL;
  552.     while (1)
  553.     {
  554.         p = malloc(numbytes);
  555.         if (p == NULL)
  556.         {    if (mem_exception())
  557.                 continue;
  558.         }
  559.         else
  560.             mem_count++;
  561.         break;
  562.     }
  563.     /*printf("malloc(%d) = x%lx\n",numbytes,p);*/
  564.     return p;
  565. }
  566.  
  567. /***************************/
  568.  
  569. void *mem_calloc(numbytes)
  570. unsigned numbytes;
  571. {    void *p;
  572.  
  573.     if (numbytes == 0)
  574.         return NULL;
  575.     while (1)
  576.     {
  577.         p = calloc(numbytes,1);
  578.         if (p == NULL)
  579.         {    if (mem_exception())
  580.                 continue;
  581.         }
  582.         else
  583.             mem_count++;
  584.         break;
  585.     }
  586.     /*printf("calloc(%d) = x%lx\n",numbytes,p);*/
  587.     return p;
  588. }
  589.  
  590. /***************************/
  591.  
  592. void *mem_realloc(oldmem_ptr,newnumbytes)
  593. void *oldmem_ptr;
  594. unsigned newnumbytes;
  595. {   void *p;
  596.  
  597.     if (oldmem_ptr == NULL)
  598.     p = mem_malloc(newnumbytes);
  599.     else if (newnumbytes == 0)
  600.     {    mem_free(oldmem_ptr);
  601.     p = NULL;
  602.     }
  603.     else
  604.     {
  605.     do
  606.         p = realloc(oldmem_ptr,newnumbytes);
  607.     while (p == NULL && mem_exception());
  608.     }
  609.     /*printf("realloc(x%lx,%d) = x%lx\n",oldmem_ptr,newnumbytes,p);*/
  610.     return p;
  611. }
  612.  
  613. /***************************/
  614.  
  615. void mem_free(ptr)
  616. void *ptr;
  617. {
  618.     /*printf("free(x%lx)\n",ptr);*/
  619.     if (ptr != NULL)
  620.     {    assert(mem_count > 0);
  621.     mem_count--;
  622. #if DLC
  623.     {    int i;
  624.  
  625.         i = free(ptr);
  626.         assert(i == 0);
  627.     }
  628. #else
  629.     free(ptr);
  630. #endif
  631.     }
  632. }
  633.  
  634. #if __ZTC__
  635.  
  636. /* Minimum size of a free block    */
  637. #define MINBLKSIZE    (sizeof(size_t) + sizeof(void *))
  638. /* Boundary that allocations are aligned on    */
  639. #define ALIGNSIZE    (sizeof(size_t))
  640.  
  641. /*****************************/
  642.  
  643. void *mem_scalloc(numbytes)
  644. size_t numbytes;
  645. {   size_t *p;
  646.  
  647.     if (numbytes == 0)
  648.     return NULL;
  649.     if (numbytes < MINBLKSIZE)
  650.     numbytes = MINBLKSIZE;
  651.     else
  652.     numbytes = (numbytes + (ALIGNSIZE - 1)) & ~(ALIGNSIZE - 1);
  653.     p = (size_t *) mem_calloc(numbytes - sizeof(size_t));
  654.     if (p)
  655.     {
  656.     p--;
  657.     *p = 0;
  658.     mem_count--;
  659.     mem_scount++;
  660.     }
  661.     return p;
  662. }
  663.  
  664. /*****************************/
  665.  
  666. void mem_sfree(ptr,numbytes)
  667. void *ptr;
  668. size_t numbytes;
  669. {
  670.     if (ptr != NULL)
  671.     {    assert(mem_scount > 0);
  672.     mem_scount--;
  673.     if (numbytes < MINBLKSIZE)
  674.         numbytes = MINBLKSIZE;
  675.     else
  676.         numbytes = (numbytes + (ALIGNSIZE - 1)) & ~(ALIGNSIZE - 1);
  677.     *((size_t *)ptr)++ = numbytes;    /* store size of free block    */
  678.     free(ptr);
  679.     }
  680. }
  681.  
  682. #endif /* __ZTC__ */
  683.  
  684. #endif
  685.  
  686. /***************************/
  687.  
  688. void mem_init()
  689. {
  690.     if (mem_inited == 0)
  691.     {    mem_count = 0;
  692. #if MEM_DEBUG
  693.         mem_numalloc = 0;
  694.         mem_maxalloc = 0;
  695.         mem_alloclist.next = NULL;
  696. #endif
  697. #if __ZTC__
  698.         /* Necessary if mem_sfree() calls free() before any    */
  699.         /* calls to malloc().                    */
  700.         free(malloc(1));    /* initialize storage allocator    */
  701. #endif
  702.         mem_inited++;
  703.     }
  704. }
  705.  
  706. /***************************/
  707.  
  708. void mem_term()
  709. {
  710.  
  711.     if (mem_inited)
  712.     {
  713. #if MEM_DEBUG
  714.         register struct mem_debug *dl;
  715.  
  716.         for (dl = mem_alloclist.next; dl; dl = dl->next)
  717.         {    fprintf(ferr,"Unfreed pointer: ");
  718.             mem_printdl(dl);
  719.         }
  720. #if 0
  721.         fprintf(ferr,"Max amount ever allocated == %ld bytes\n",
  722.             mem_maxalloc);
  723. #endif
  724. #else
  725.         if (mem_count)
  726.             fprintf(ferr,"%d unfreed items\n",mem_count);
  727.         if (mem_scount)
  728.             fprintf(ferr,"%d unfreed s items\n",mem_scount);
  729. #endif /* MEM_DEBUG */
  730.         assert(mem_count == 0 && mem_scount == 0);
  731.         mem_inited = 0;
  732.     }
  733. }
  734.  
  735. #undef next
  736. #undef prev
  737. #undef file
  738. #undef line
  739. #undef nbytes
  740. #undef beforeval
  741.  
  742.